#include "ViewerWrapper.h"

#include "iostream"
#include <memory>
#include <odv/odvCore/ViewerEvent.h>
#include <pybind11/stl.h>

#include <odv/odvCore/LayerOptions.h>
#include <odv/odvCore/Viewer.h>
#include <odv/odvCore/ViewerOptions.h>

namespace py = pybind11;

void bind_CoordinateSystem(py::module_ &m) {
  py::enum_<odv::CoordinateSystem>(m, "CoordinateSystem")
      .value("Geographic", odv::CoordinateSystem::Geographic)
      .value("Projected", odv::CoordinateSystem::Projected)
      .export_values();
}

void bind_MapProjection(py::module_ &m) {
  py::enum_<odv::MapProjection>(m, "MapProjection")
      .value("Geographic", odv::MapProjection::EquidistantCylindrical)
      .value("Mercator", odv::MapProjection::Mercator)
      .value("LambertAsia", odv::MapProjection::LambertAsia)
      .value("UTM50N", odv::MapProjection::UTM50N)
      .value("UTM51N", odv::MapProjection::UTM51N)
      .value("TokyoUTM51N", odv::MapProjection::TokyoUTM51N)
      .value("GaussKruger21", odv::MapProjection::GaussKruger21)
      .value("SouthChinaSeaLambert", odv::MapProjection::SouthChinaSeaLambert)
      .export_values();
}

void bind_Viewer(py::module_ &m) {
  py::class_<odv::Viewer, std::shared_ptr<odv::Viewer>>(m, "Viewer")
      // 构造函数
      .def(py::init<odv::CoordinateSystem, odv::MapProjection>(),
           py::arg("cs") = odv::CoordinateSystem::Projected,
           py::arg("mp") = odv::MapProjection::EquidistantCylindrical)

      // 析构函数（自动处理）

      // 坐标系统和投影设置
      .def("setCoordinateSystemAndMapProjection",
           &odv::Viewer::setCoordinateSystemAndMapProjection, py::arg("cs"),
           py::arg("mp"), py::arg("clearLayers") = true)

      // 窗口设置
      .def("setUpViewInWindow", &odv::Viewer::setUpViewInWindow, py::arg("x"),
           py::arg("y"), py::arg("width"), py::arg("height"))

      .def("setUpViewerAsEmbeddedInWindow",
           &odv::Viewer::setUpViewerAsEmbeddedInWindow, py::arg("x"),
           py::arg("y"), py::arg("width"), py::arg("height"))

      // 视图控制
      .def("realize", &odv::Viewer::realize)
      .def("done", &odv::Viewer::done)
      .def("frame", &odv::Viewer::frame)
      .def("run", &odv::Viewer::run)

      // 名称设置
      .def("setName", &odv::Viewer::setName, py::arg("name"))
      .def("getName", &odv::Viewer::getName)

      // OSG uniforms 设置
      .def("setUseOsgModelViewAndProjectionUniforms",
           &odv::Viewer::setUseOsgModelViewAndProjectionUniforms,
           py::arg("flag"))

      .def("addLayer",
           py::overload_cast<std::shared_ptr<odv::LayerOptions>>(
               &odv::Viewer::addLayer),
           py::arg("options"))

      .def("updateLayer", &odv::Viewer::updateLayer, py::arg("id"),
           py::arg("options"))

      .def("removeLayer", &odv::Viewer::removeLayer, py::arg("id"))

      .def("setLayerVisible", &odv::Viewer::setLayerVisible, py::arg("id"),
           py::arg("visible"))

      .def("isLayerVisible", &odv::Viewer::isLayerVisible, py::arg("id"))

      .def("getLayerOptions", &odv::Viewer::getLayerOptions, py::arg("id"))

      .def("setLayerOrder", &odv::Viewer::setLayerOrder, py::arg("id"),
           py::arg("order"))

      .def("getLayerOrder", &odv::Viewer::getLayerOrder, py::arg("id"))

      .def("moveLayerAbove", &odv::Viewer::moveLayerAbove,
           py::arg("layerToMoveId"), py::arg("aboveLayerId"))

      .def("moveLayerBelow", &odv::Viewer::moveLayerBelow,
           py::arg("layerToMoveId"), py::arg("belowLayerId"))

      .def("remove_handler", &odv::Viewer::removeHandler,
           py::arg("handler_name"))

      .def(
          "addKeybordHandler",
          [](odv::Viewer &self, const std::string &name,
             py::function py_callback) {
            odv::ViewerKeyEventCallback cpp_callback =
                [py_callback](odv::Viewer *viewer, odv::EventType eventType,
                              int key) {
                  try {
                    py_callback(viewer, eventType, key);
                  } catch (py::error_already_set &e) {
                    std::cerr << "Keyboard handler error: " << e.what() << "\n";
                  }
                };
            self.addKeybordHandler(name, cpp_callback);
          },
          py::arg("handlerName"), py::arg("handlerCallback"))

      .def(
          "addMouseButtonHandler",
          [](odv::Viewer &self, const std::string &name,
             py::function py_callback) {
            odv::ViewerMouseButtonEventCallback cpp_callback =
                [py_callback](odv::Viewer *viewer, odv::EventType eventType,
                              odv::MouseButton button, int x, int y) {
                  try {
                    py_callback(viewer, eventType, button, x, y);
                  } catch (py::error_already_set &e) {
                    std::cerr << "MouseButton handler error: " << e.what()
                              << "\n";
                  }
                };
            self.addMouseButtonHandler(name, cpp_callback);
          },
          py::arg("handlerName"), py::arg("handlerCallback"));
}
